/**
 * 
 */
package main;

import daos.DAOs;
import exceptions.BadParametersException;

import exceptions.ChildLoanException;
import exceptions.ExtensionBackDateException;
import exceptions.LentMediaException;
import exceptions.MediaExistsException;
import exceptions.ReservationMediaException;
import exceptions.SubscriberExistsException;

import hibernateUtils.HibernateUtil;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import subscribersManagement.Subscriber;





import loansManagement.Loan;
import loansManagement.Reservation;
import mediasManagement.Exemplary;
import mediasManagement.Media;
import java.util.Collection;

import org.hibernate.Session;

/** 
 * @author virgil
 */
public class Library {



	
	/** 
	 * Add a media
	 * @throws MediaExistsException 
	 */
	public void addMedia(Media media)	throws BadParametersException, MediaExistsException {
		if (media == null)
			throw new BadParametersException();

		// Look if the media is already in the library
		if (isAMedia(media)){
			addExemplaryMedia(media);
		}
		else
			this.medias.add(media);
			
			DAOs.getMediaDAO().add(media);
			
		}
	

	
	/**
	 */
	public void addExemplaryMedia(Media media) throws BadParametersException, MediaExistsException{
		if (media == null)
			throw new BadParametersException();
		
		if (!((isAMedia(media))||DAOs.getMediaDAO().contains(media)))
			throw new MediaExistsException();
		
		int index = this.medias.indexOf(media);
		
		Exemplary exemplary= new Exemplary(this.medias.get(index));
		this.medias.get(index).addExemplary(exemplary);
		DAOs.getMediaDAO().addExemplary(media);
	}

	public void addSubscriber(Subscriber subsriber) throws BadParametersException, SubscriberExistsException, MediaExistsException
		 {
	if (subsriber == null)
		throw new BadParametersException();
	
	if (isASubscriber(subsriber))
		throw new SubscriberExistsException();
	
	DAOs.getSubscriberDAO().add(subsriber);
	subscribers.add(subsriber);
}
	
	public boolean isASubscriber(Subscriber subscriber) throws SubscriberExistsException, BadParametersException, MediaExistsException {
		if(subscriber == null)
			throw new BadParametersException();
		return (DAOs.getSubscriberDAO().contains(subscriber));
				
	}


	/**
	 * @throws BadParametersException 
	 * @throws MediaExistsException 
	 */
	public Boolean isAMedia(Media media) throws BadParametersException, MediaExistsException{
		
		if (media == null)
			throw new BadParametersException();
		
		// If the object is in the list,
		// it is a known media
		return (DAOs.getMediaDAO().contains(media));
	}



	/**
	 * @uml.property   name="medias"
	 * @uml.associationEnd   multiplicity="(0 -1)" ordering="true" inverse="library:mediasManagement.Media"
	 */
	private ArrayList<Media> medias = new ArrayList<Media>();



	/** 
	 * Getter of the property <tt>medias</tt>
	 * @return  Returns the media.
	 * @uml.property  name="medias"
	 */
	public ArrayList<Media> getMedias() {
		return medias;
	}


	/** 
	 * Setter of the property <tt>medias</tt>
	 * @param medias  The media to set.
	 * @uml.property  name="medias"
	 */
	public void setMedias(ArrayList<Media> medias) {
		this.medias = medias;
	}



	/**
	 * @uml.property   name="loans"
	 * @uml.associationEnd   multiplicity="(0 -1)" ordering="true" inverse="library:loansManagement.Loan"
	 */
	private ArrayList<Loan> loans = new ArrayList<Loan>();



	/** 
	 * Getter of the property <tt>loans</tt>
	 * @return  Returns the loans.
	 * @uml.property  name="loans"
	 */
	public ArrayList<Loan> getLoans() {
		return loans;
	}


	/** 
	 * Setter of the property <tt>loans</tt>
	 * @param loans  The loans to set.
	 * @uml.property  name="loans"
	 */
	public void setLoans(ArrayList<Loan> loans) {
		this.loans = loans;
	}



	/**
		 * @return 
		 * @throws LentMediaException 
		 * @throws BadParametersException 
		 * @throws ChildLoanException 
	 * @throws MediaExistsException 
	 * @throws SubscriberExistsException 
		 */
		public Calendar lend(Subscriber lender, Media media) throws BadParametersException, 
		LentMediaException, ChildLoanException, MediaExistsException, SubscriberExistsException{
			if (media == null || lender == null)
				throw new BadParametersException();

			// Check if the book exists
			if (!isAMedia(media))
				throw new MediaExistsException();

			// Check if the subscriber exists
			if (!isASubscriber(lender))
				throw new SubscriberExistsException();
			
			Media x= DAOs.getMediaDAO().get(media.getMediaNumberId());
			Subscriber y= DAOs.getSubscriberDAO().GetSingleSubscriberByLastName(lender.getLastName());
			Loan l = new Loan(media, lender);
			System.out.println(l.getExemplary().getExemplaryId());
			this.loans.add(l);
			return l.getReturnDate();
		}
		
		public void returnMedia(String exemplaryId) throws MediaExistsException, SubscriberExistsException, BadParametersException, ReservationMediaException, ChildLoanException{
			if (exemplaryId.isEmpty()) throw new  BadParametersException();
			Exemplary ex= DAOs.getMediaDAO().getExamplary(exemplaryId);
			Loan l= ex.getCurrentLoan();
			l.setIsReturn(true);
			Subscriber s= DAOs.getSubscriberDAO().GetSubscriberById(l.getLender().getNumber());
			ex.setCurrentLoan(l);
			s.getCurrentloans().add(l);
			HibernateUtil.openSession().merge(ex);
			HibernateUtil.openSession().merge(s);
			sendMailReservation(exemplaryId);
		}

		public void extendDateReturnMedia(String exemplaryId) throws MediaExistsException, SubscriberExistsException, BadParametersException, ExtensionBackDateException{
			if (exemplaryId.isEmpty()) throw new  BadParametersException();
			Exemplary ex= DAOs.getMediaDAO().getExamplary(exemplaryId);
			
			if(ex.getMedia().getNumberAvailableExemplary()<ex.getMedia().getReservations().size())
				throw  new ExtensionBackDateException();
			
			Loan l= ex.getCurrentLoan();
			l.getReturnDate().add(Calendar.MONTH, Constraints.loanDELAY);
			Subscriber s= DAOs.getSubscriberDAO().GetSubscriberById(l.getLender().getNumber());
			ex.setCurrentLoan(l);
			s.getCurrentloans().add(l);
			HibernateUtil.openSession().merge(ex);
			HibernateUtil.openSession().merge(s);
		}
		
		
		public void reserve(Subscriber lender, Media media) throws BadParametersException, 
		LentMediaException, ChildLoanException, MediaExistsException, SubscriberExistsException, ReservationMediaException{
			if (media == null || lender == null)
				throw new BadParametersException();

			// Check if the book exists
			if (!isAMedia(media))
				throw new MediaExistsException();

			// Check if the subscriber exists
			if (!isASubscriber(lender))
				throw new SubscriberExistsException();
			
			Reservation r  = new Reservation(media, lender);
	
			this.reservations.add(r);

			
		}
		
		
		public void cancelReservation(Subscriber lender, Media media) throws MediaExistsException, SubscriberExistsException, BadParametersException{
			if (media == null || lender == null)
				throw new BadParametersException();

			// Check if the book exists
			if (!isAMedia(media))
				throw new MediaExistsException();

			// Check if the subscriber exists
			if (!isASubscriber(lender))
				throw new SubscriberExistsException();
			Exemplary ex=null;
			Reservation r= new Reservation();
			
			r.setMedia(media);
			r.setSubscriber(lender);
			for(Reservation r1:lender.getReservations()){
				if(r1.equals(r)){
					ex=DAOs.getMediaDAO().getExamplary(r1.getExemplaryId());
					break;
				}
			}
			if (ex!=null){
				ex.setReserved(false);
				Session session=HibernateUtil.openSession();
				session.merge(ex);
			}
			lender.getReservations().remove(r);
			media.getReservations().remove(r);
		}
	/**
	 * @uml.property  name="subscribers"
	 * @uml.associationEnd  multiplicity="(0 -1)" ordering="true" inverse="library:subscribersManagement.Subscriber"
	 */
		
		public void printCurrentLoans(){
			loans = (ArrayList<Loan>) DAOs.getLoanDAO().findAll();
			for (Loan l : loans) {
				System.out.println(l.toString());
			}
		}
		
		public void sendMailReservation(String exemplaryId) throws MediaExistsException, BadParametersException, ReservationMediaException, ChildLoanException{
			Exemplary ex=DAOs.getMediaDAO().getExamplary(exemplaryId);
			Media media=ex.getMedia();
			Subscriber s = null;
			Reservation ra= new Reservation();
			ra.setMedia(media);
			if(!media.getReservations().isEmpty()){
				
				for(Reservation r:media.getReservations()){
					
					if(r.getExemplaryId()==null){
						s=r.getSubscriber();
						ra.setSubscriber(s);
						break;
					}
				}
				s.getReservations().remove(ra);
				media.getReservations().remove(ra);
				ra=new Reservation(media,s);
		}
		}

		public void printCurrentReservations(){
			reservations=(ArrayList<Reservation>) DAOs.getLoanDAO().findAllReservations();
			for(Reservation r:  reservations){	
						System.out.println(r.toString());	
			}
		}
		
		public void searchMediaByName(String mediaName) throws MediaExistsException, BadParametersException{
			if(mediaName.isEmpty())
				throw new BadParametersException();
			
			ArrayList<Media> m= (ArrayList<Media>) DAOs.getMediaDAO().findAllByName(mediaName);
			
			if (m.size()==0)
				throw new MediaExistsException();
			
			for(Media me:m){
				System.out.println(me.toString());
			}
		}
		
		public void searchMediaById(String mediaNumberId) throws BadParametersException, MediaExistsException{
			if(mediaNumberId.isEmpty())
				throw new BadParametersException();
			
			Media m= DAOs.getMediaDAO().get(mediaNumberId);
			
			System.out.println(m.toString());
			
		}
		
		public void searchSubscriberByName(String mediaName) throws MediaExistsException, BadParametersException, SubscriberExistsException{
			if(mediaName.isEmpty())
				throw new BadParametersException();
			
			ArrayList<Subscriber> s= (ArrayList<Subscriber>) DAOs.getSubscriberDAO().findAllByName(mediaName);
			
			if (s.size()==0)
				throw new SubscriberExistsException();
			
			for(Subscriber se:s){
				System.out.println(se.toString());
			}
		}
		
		public void searchSubscriberById(long numberId) throws BadParametersException, MediaExistsException, SubscriberExistsException{
			if(numberId==0)
				throw new BadParametersException();
			
			Subscriber s= DAOs.getSubscriberDAO().GetSubscriberById(numberId);
			
			System.out.println(s.toString());
			
		}
	private ArrayList subscribers = new ArrayList<Subscriber>();



	/**
	 * Getter of the property <tt>subscribers</tt>
	 * @return  Returns the subscribers.
	 * @uml.property  name="subscribers"
	 */
	public ArrayList getSubscribers() {
		return subscribers;
	}


	/**
	 * Setter of the property <tt>subscribers</tt>
	 * @param subscribers  The subscribers to set.
	 * @uml.property  name="subscribers"
	 */
	public void setSubscribers(ArrayList subscribers) {
		this.subscribers = subscribers;
	}



	/**
	 * @uml.property  name="reservations"
	 * @uml.associationEnd  multiplicity="(0 -1)" inverse="library:loansManagement.Reservation"
	 */
	private ArrayList<Reservation> reservations = new ArrayList<Reservation>();



	/**
	 * Getter of the property <tt>reservations</tt>
	 * @return  Returns the reservations.
	 * @uml.property  name="reservations"
	 */
	public ArrayList<Reservation> getReservations() {
		return reservations;
	}



	/**
	 * Setter of the property <tt>reservations</tt>
	 * @param reservations  The reservations to set.
	 * @uml.property  name="reservations"
	 */
	public void setReservations(ArrayList<Reservation> reservations) {
		this.reservations = reservations;
	}

}
